#pragma once


/**
Predefined error codes.
These are used by the PG_ERROR makro and therefore by pgPaleGemFramework::HandleException().
*/
enum PG_ERROR
{
	ER_NOT_ENOUGH_PHYS_RAM = 1,
	ER_NOT_ENOUGH_VIRT_RAM,
	ER_NOT_ENOUGH_HARD_DISK_SPACE,
	ER_NULL_POINTER,
	ER_D3D_INIT_FAILURE,
	ER_INVALID_PATH,
};

/**
Interface for the game to the engine.

General information:
--------------------
The PaleGem engine framework represents the engine at its toplayer. Without it, the engine will not work
and also isn't usable in the first place. 
The framework is a singleton class and therefore should not be instanced.
Instead the makro g_PG_pPaleGemFramework can be used to access the framework and its subsystems.
Note that in the future (or if the future has come already, now) g_PG_pPaleGemFramework and g_PG_pSGameInfo are
the only two globally accessible interfaces for the engine. 
Any other subsystems reside inside the framework, however makros are provided to ease accession of these systems.
These makros are:
	- g_PG_pRenderer
	@see pgRender
	- g_PG_pTimer
	@see pgTimer
	- g_PG_pFrameworkEventManager
	@see pgEventManager
	- listend

Initializing the framework:
---------------------------
@see SGameInfo

BEFORE you call pgInit(), you will have to provide some information for the framework.
This is done by calling g_PG_pSGameInfo->SetInfo(). If you don't provide a window handle (provide NULL for the hWindow param)
the engine will create a window and name its class and the window itself after the game title you provided. 
If you fail to call g_PG_pSGameInfo->SetInfo(), the game info subsystem will try to use defaults.
This is not supported and no warranty whatsoever is provided for it to function.

Updating your game:
-------------------
@see EVENT_NAME

There are several ways to go about updating the engine and your game.
You can either:
	- call pgDoMessageLoop() AFTER you called pgInit(). This will enter a while loop inside the engine
	which will handle the windows message loop. It will call pgUpdate() which itself is responsible
	for the actual updating of the engine and its subsystems. By using this method the only way for your game 
	to receive updates is to register a class with g_PG_pPaleGemFremawork->GetFrameworkEventManager()->RegisterListener().

	- call pgUpdate to manually update the engine in your own windows message loop.

	- call pgDoMessageLoop(int (*Update) (float frameTime)), where Update is a function you provide. This way you don't need to use
	the framework event manager to update your game.

	- call each subsystem's update function manually in your own message loop. 
	This might just be the best solution as you can control precisely when which system
	will be updated.
	@see pgPaleGemFramework::pgUpdate()

*/
class IPaleGemFramework
{
public:
	/**
	Initialises the game engine and creates a game window.
	@param hInstance	HINSTANCE arg of WinMain
	@param cmdShow		nCmdShow of WinMain
	@param lpGameTitle	Name of the game, will also be name of the windowclass and windowtitle
	@returns S_OK if everything went well otherwise see log
	*/
	virtual HRESULT pgInit(HINSTANCE hInstance, int cmdShow, LPCWSTR lpGameTitle) = 0;

	/**
	Updates the engine and its subsystems
	*/
	virtual void pgUpdate() = 0;

	/**
	Shuts the engine down
	*/
	virtual HRESULT pgExit() = 0;

	/**
	Enters the windows message loop.
	@see Updating your game
	*/
	virtual void	pgDoMessageLoop() = 0;

	/**
	Enters the windows message loop and calls UpdateFunction before updating the engine.
	@param UpdateFunction Pointer to your game's update function.
	@see Updating your game
	*/
	virtual void	pgDoMessageLoop(int (*UpdateFunction) (float fFrameTime)) = 0;

	/**
	Checks if there's allready an instance of the game running.
	@param lpGameTitle	Name of the game to check for
	@returns true if there's already an instance running
	*/
	virtual bool pgCheckForMultipleInstances(LPCWSTR lpGameTitle) = 0;

	/**
	Checks available memory on harddisk and returns true if theres enough.
	@params spaceNeeded The space to check for in bytes
	@returns True if there's enough space to host spaceNeeded
	*/
	virtual bool pgCheckHardDiskSpace(const DWORDLONG spaceNeeded) = 0;
	
	/*
	#pgCheckRAM
	Checks the available system RAM
	#Params
	spaceNeeded:	The space to check for in bytes
	#Returns
	True if theres >= spaceNeeded
	*/
	virtual bool pgCheckRAM(const DWORDLONG spaceNeeded) = 0;

	/*
	#pgCheckAvailRAM
	Check the available total RAM
	#Params
	spaceNeeded:	The space to check for in bytes
	#Returns
	True if enough space is available
	*/
	virtual bool pgCheckAvailRAM(const DWORDLONG spaceNeeded) = 0;

};